package com.cskaoyan.mall.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.cskaoyan.mall.common.constant.ResultCodeEnum;
import com.cskaoyan.mall.common.result.Result;
import com.cskaoyan.mall.common.util.IpUtil;
import com.cskaoyan.mall.user.consts.UserConstants;
import com.cskaoyan.mall.user.dto.UserLoginInfoDTO;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;

@Component
public class AuthFilet implements GlobalFilter {
    @Autowired
    RedissonClient redissonClient;

    @Value("${authUrls.url}")
    String preventUrl;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //在这个地方过滤请求等内容
        //1. 获取请求
        ServerHttpRequest request=exchange.getRequest();

        //2.获取响应
        ServerHttpResponse response = exchange.getResponse();

        //获取登录信息
        String useId = isLogin(request);
        if ("-1".equals(useId)){
            return out(response, ResultCodeEnum.ILLEGAL_REQUEST);
        }

        //获取是否需要拦截
        boolean needDoPrevent=needPrevent(request);

        //需要拦截并且没有登录信息
        if (needDoPrevent&&useId==null){
            return out(response, ResultCodeEnum.LOGIN_AUTH);
        }

        //不需要拦截并且没有登录信息
        if (!needDoPrevent&&useId==null){
            return chain.filter(exchange);
        }

        //然后把登录信息放入请求头，放行即可
        ServerHttpRequest.Builder requestBuilder = request.mutate();
        requestBuilder.header("userId",useId);
        //然后要判断cookie里面是否有tempId
        HttpCookie userTempId = request.getCookies().getFirst("userTempId");
        if (userTempId!=null){
            requestBuilder.header("userTempId",userTempId.getValue());
        }
        ServerHttpRequest build = requestBuilder.build();
        ServerWebExchange newExchange = exchange.mutate().request(build).build();


        return chain.filter(newExchange);
    }

    private boolean needPrevent(ServerHttpRequest request) {
        String path = request.getURI().getPath();
        //然还还给了个判断的uri，想想在哪
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        return antPathMatcher.match(preventUrl, path);
    }

    //null,未登录 -1 ip错误 其余，正常登录
    private String isLogin(ServerHttpRequest request) {
        //先获取请求头内容，判断是否携带token（令牌）
        HttpHeaders headers = request.getHeaders();
        String token = headers.getFirst("token");
        if (StringUtils.isBlank(token)){
            //token是空
            HttpCookie cookie = request.getCookies().getFirst("token");
            if (cookie!=null&&StringUtils.isNotBlank(cookie.getValue()))token=cookie.getValue();
        }


        if (StringUtils.isNotBlank(token)){
            RBucket<UserLoginInfoDTO> bucket = redissonClient.getBucket(UserConstants.USER_LOGIN_KEY_PREFIX + token);
//            UserLoginInfoDTO userLoginInfoDTO = bucket.get();
            UserLoginInfoDTO userLoginInfoDTO = bucket.get();
            if (userLoginInfoDTO==null)return null;
            if (!Objects.equals(IpUtil.getGatwayIpAddress(request), userLoginInfoDTO.getIp())){
                //要删除redis内的相关内容
                return "-1";
            }

            return userLoginInfoDTO.getUserId();
        }
        return null;
    }

    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum){
        Result<Object> result = Result.build(null, resultCodeEnum);
        byte[] bytes = JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8);
        DataBuffer wrap = response.bufferFactory().wrap(bytes);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");

        return response.writeWith(Mono.just(wrap));

    }

}
